﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Sustainalytics.Reporting.Framework;
using Foxit.PDF.PageElements;
using Foxit.PDF;
using Foxit.PDF.Imaging;
using Sustainalytics.Entities;
using Image = Foxit.PDF.PageElements.Image;
using Sustainalytics.Entities.Governance;
using Sustainalytics.Utils;

namespace Sustainalytics.Governance.Reporting
{
    public class CompanyOverviewSection : PdfReportSectionGenerator
    {       
        # region Static Images

        private static byte[] _companyLogoHeaderImage;
        private static byte[] _companyLogoFooterImage;
        public byte[] CompanyLogoHeaderImage { get { return _companyLogoHeaderImage; } }
        public byte[] CompanyLogoFooterImage { get { return _companyLogoFooterImage; } }

        private static byte[] _outlookArrowDown;
        private static byte[] _outlookArrowUp;
        private static byte[] _outlookArrowRight;
        public byte[] OutlookArrowDown { get { return _outlookArrowDown; } }
        public byte[] OutlookArrowUp { get { return _outlookArrowUp; } }
        public byte[] OutlookArrowRight { get { return _outlookArrowRight; } }


        private static void LoadStaticImages()
        {
            if (_companyLogoHeaderImage == null)
                _companyLogoHeaderImage = ImageManager.GetJpgImage(@"Images\sustaynalytics_logo_header.jpg");

            if (_companyLogoFooterImage == null)
                _companyLogoFooterImage = ImageManager.GetJpgImage(@"Images\sustaynalytics_logo_footer.jpg");

            if (_outlookArrowDown == null)
                _outlookArrowDown = ImageManager.GetJpgImage(@"Images\outlook_arrow_down.jpg");

            if (_outlookArrowUp == null)
                _outlookArrowUp = ImageManager.GetJpgImage(@"Images\outlook_arrow_up.jpg");

            if (_outlookArrowRight == null)
                _outlookArrowRight = ImageManager.GetJpgImage(@"Images\outlook_arrow_right.jpg");

        }

        #endregion

        static CompanyOverviewSection()
        {           
            LoadStaticImages();
        }

        public override void ComposeSectionContent()
        {
            const float companyInfoPosition = 100f;
            const float summaryTitlePosition = 135f;

            float overallPerformancePosition;
            float relativePerformancePosition;
            float relativePerformancePositionDetails = 440f;

            var page = _report.NewPage();
            _report.Pages.Add(page);

            Table table;

            AddHeaderToPage(page);
            AddCompanyInfo(page, _report.LeftMargin, companyInfoPosition);
            
            table = AddSummaryTitle(summaryTitlePosition);
            page.Elements.Add(table);

            if (_dataSource.CompanyProfile.FullProfile)
            {
                overallPerformancePosition = summaryTitlePosition + 45f;

                table = AddOverallPerformance(page, overallPerformancePosition);
                page.Elements.Add(table);

                relativePerformancePosition = overallPerformancePosition + 120f;


                AddRelativePerformance(page, _report.LeftMargin, relativePerformancePosition);

                if (_dataSource.IssuesPerformance != null)
                {
                    table = AddRelativePerformanceDetails(relativePerformancePositionDetails);
                    page.Elements.Add(table);
                }

                page = _report.NewPage();
                _report.Pages.Add(page);

                table = AddAnalystView();
                page.Elements.Add(table);
            }
            else
            {
                const float overviewPosition = summaryTitlePosition + 35f;
                table = AddOverview(overviewPosition);
                page.Elements.Add(table);
                var overviewHeight = table.GetVisibleHeight();

                overallPerformancePosition = overviewPosition + overviewHeight + 10f;

                table = AddOverallPerformance(page, overallPerformancePosition);
                page.Elements.Add(table);

                var overallPerformanceHeight = table.GetRequiredHeight();

                relativePerformancePosition = 60 + overallPerformancePosition + overallPerformanceHeight + 10f;

                AddRelativePerformance(page, _report.LeftMargin, relativePerformancePosition);

                relativePerformancePositionDetails = relativePerformancePosition + 130f;

                if (_dataSource.IssuesPerformance != null)
                {
                    table = AddRelativePerformanceDetails(relativePerformancePositionDetails);
                    page.Elements.Add(table);
                }
            }
        }

        private void AddHeaderToPage(PdfReportPage page)
        {
            const float top = 15f;

            var firstCompanyNameLine = string.Empty;
            var secondCompanyNameLine = string.Empty;
            var companyNameLines = BuildCompanyNameLines(_dataSource.CompanyProfile.CompanyName);
            if (companyNameLines.Any())
            {
                firstCompanyNameLine = companyNameLines[0];
                if (companyNameLines.Count() == 2)
                {
                    secondCompanyNameLine = companyNameLines[1];
                }
            }


            var styleCompanyName = new FormattedTextAreaStyle(Fonts.CalibriFontFamily, 22f, true)
            {
                Paragraph = {Align = TextAlign.Left, Indent = 0, SpacingAfter = 0, AllowOrphanLines = false},
                Bold = true
            };

            //The company name text span considered 
            const float compTxtAreaSpan = 320f;

            var width = _report.PageMaxWidth;
            var height = _report.PageMaxHeight - 25f;

            var table = GetDefaultTable(_report.LeftMargin, top, width, height);

            table.Columns.Add(width * 0.6f);
            table.Columns.Add(width * 0.4f);

            var row1 = table.Rows.Add(16);
            var row2 = table.Rows.Add(16);

               
            var companyNameText = new FormattedTextArea($"<p>{firstCompanyNameLine}</p>", 0, 0, compTxtAreaSpan,
                14f, styleCompanyName);

            var cell = row1.Cells.Add(companyNameText);
            cell.VAlign = VAlign.Top;
            cell.Align = TextAlign.Left;

            if (companyNameLines.Count == 1)
            {
                cell.Padding.Top = 8f;
            }

            cell = row1.Cells.Add(new Image(ImageData.GetImage(_companyLogoHeaderImage), 0, 0, 0.25f), 0, 2);
            cell.Align = TextAlign.Right;
            cell.VAlign = VAlign.Top;

    
            var overflowCompanyNameTextArea = new FormattedTextArea($"<p>{secondCompanyNameLine}</p>", 0, 0,
                compTxtAreaSpan, 14f, styleCompanyName);

            cell = row2.Cells.Add(overflowCompanyNameTextArea);
            cell.VAlign = VAlign.Top;
            cell.Align = TextAlign.Left;
            cell.Padding.Value = 0.0f;
            cell.Padding.Top = 0f;



            var row = table.Rows.Add(10);
            cell = row.Cells.Add("CORPORATE GOVERNANCE",
                Fonts.CalibriBold, 12, RgbColor.DarkGray, RgbColor.White, 2);
            cell.Align = TextAlign.Right;
            cell.VAlign = VAlign.Center;

            row = table.Rows.Add(10);
            cell = row.Cells.Add("COMPANY REPORT",
                Fonts.CalibriBold, 12, RgbColor.DarkGray, RgbColor.White, 2);
            cell.Align = TextAlign.Right;
            cell.VAlign = VAlign.Center;
            cell.Border.Bottom.LineStyle = LineStyle.Solid;
            cell.Border.Bottom.Width = 1.5f;
            cell.Border.Bottom.Color = RgbColor.DarkGray;

            page.Elements.Add(table);
        }

        private List<string> BuildCompanyNameLines(string companyName)
        {
            List<string> generatedList = new List<string>();

            int lastIndexOfSpace = 0;
            int lastIndexOfLine = 0;

            int maxIndex;
            int refIndex = 0;
            int consideredNrChars = 28;
            int remainingLength;

            string firstLine;
            string secondLine;


            //Compute 1st line
            for (int i = 0; i < companyName.Length; i++)
            {
                if (companyName[i].Equals(' '))
                {
                    lastIndexOfSpace = i;
                }
                else if (companyName[i].Equals('-'))
                {
                    lastIndexOfLine = i;
                }

                //reached 28 characters long, reset counter index and build 1st line from Company Name; while admitting 29 chars max 
                if (i == consideredNrChars)
                {
                    maxIndex = Math.Max(lastIndexOfSpace, lastIndexOfLine);

                    //Include space or "-" character into 1st line width for visibility & grammar purposes
                    firstLine = companyName.Substring(refIndex, maxIndex + 1);
                    generatedList.Add(firstLine);

                    refIndex = maxIndex;

                    //No longer interested in the iteration for this row
                    break;
                }
            }
            remainingLength = companyName.Length - refIndex - 1;

            //If there is a shorter 2-nd row, build it at once
            if (companyName.Length > 29 && remainingLength <= 29 && companyName.Length < 58)
            {
                secondLine = companyName.Substring(refIndex + 1, remainingLength);
                generatedList.Add(secondLine);
            }
            else if (remainingLength >= 29)
            {
                //Compute 2nd line
                for (int i = refIndex + 1; i < companyName.Length; i++)
                {
                    if (companyName[i].Equals(' '))
                    {
                        lastIndexOfSpace = i;
                    }
                    else if (companyName[i].Equals('-'))
                    {
                        lastIndexOfLine = i;
                    }

                    //reached next added 28 characters long, build 2nd line from Company Name; while admitting 29 chars max 
                    if (i == (refIndex + 1 + consideredNrChars))
                    {
                        maxIndex = Math.Max(lastIndexOfSpace, lastIndexOfLine);
                        secondLine = companyName.Substring(refIndex + 1, maxIndex - (refIndex + 1));
                        generatedList.Add(secondLine);

                        refIndex = maxIndex;
                        break;
                    }
                }
            }

            //Less than 29 chars overall, just add the company Name and it will be added on 1 row direclty
            if (!generatedList.Any())
            {
                generatedList.Add(companyName);
            }
            return generatedList;
        }

        private void AddCompanyInfo(Page page, float left, float top)
        {
            var grid = new PdfGrid
            {
                Page = page,
                Left = left,
                Top = top,
                Rows = 2,
                Columns = 3,
                Height = 30f,
                ShowGridLines = false
            };

            grid.AddChildren(new PdfLineTextBlock()
            {
                Row = 1,
                Column = 1,
                NameFont = Fonts.CalibriLight,
                ValueFont = Fonts.CalibriBold,
                FontSize = 10f,
                Name = "Industry:",
                Value = _dataSource.CompanyProfile.Industry,
                LeftOffset = 50f
            });
            grid.AddChildren(new PdfLineTextBlock()
            {
                Row = 2,
                Column = 1,
                NameFont = Fonts.CalibriLight,
                ValueFont = Fonts.CalibriBold,
                FontSize = 10f,
                Name = "Domicile:",
                Value = _dataSource.CompanyProfile.Domicile,
                LeftOffset = 50f
            });

            var marketCap = string.Empty;
            if (_dataSource.CompanyProfile.MarketCapitalization > 0)
                marketCap = string.Format("{0} mm. USD", _dataSource.CompanyProfile.MarketCapitalization.ToString("###,###,###"));

            grid.AddChildren(new PdfLineTextBlock()
            {
                Row = 1,
                Column = 2,
                NameFont = Fonts.CalibriLight,
                ValueFont = Fonts.CalibriBold,
                FontSize = 10f,
                Name = "Marketcap.:",
                Value = marketCap,
                LeftOffset = 60f
            });

            var ticker = string.Empty;
            if (!string.IsNullOrWhiteSpace(_dataSource.CompanyProfile.Ticker))
                ticker = _dataSource.CompanyProfile.Ticker;

            grid.AddChildren(new PdfLineTextBlock()
            {
                Row = 2,
                Column = 2,
                NameFont = Fonts.CalibriLight,
                ValueFont = Fonts.CalibriBold,
                FontSize = 10f,
                Name = "Ticker:",
                Value = ticker,
                LeftOffset = 60f
            });

            grid.AddChildren(new PdfLineTextBlock()
            {
                Row = 1,
                Column = 3,
                NameFont = Fonts.CalibriLight,
                ValueFont = Fonts.CalibriBold,
                FontSize = 10f,
                Name = "Employees:",
                Value = _dataSource.CompanyProfile.Employees.HasValue
                    ? _dataSource.CompanyProfile.Employees.Value.ToString("###,###,###")
                    : string.Empty,
                LeftOffset = 60f
            });
            grid.Draw();
        }


        private Table AddSummaryTitle(float top)
        {
            var width = _report.PageMaxWidth;
            const float height = 22f;

            var table = new Table(_report.LeftMargin, top, width, height);

            table.BackgroundColor = Colors.SectionColor;
            table.Border.LineStyle = LineStyle.None;
            table.CellDefault.Border.LineStyle = LineStyle.None;

            table.Columns.Add(width);

            var row = table.Rows.Add();

            const string sectionName = "<p><font color='FFFFFF'><b>Corporate Governance Summary</b></font></p>";

            var cell = row.Cells.Add(new FormattedTextArea(sectionName, 3f, 1f, width, 18f, Fonts.CalibriFontFamily, 16, false));
            cell.VAlign = VAlign.Center;
            cell.Align = TextAlign.Left;
            
            return table;
        }

        private Table AddOverallPerformance(Page page, float top)
        {
            const string sectionTitle = "Overall Performance";

            const float emptyRowHeight = 10f;
            const float sectionTitleHeight = 20f;

            const float sectionFontSize = 14f;

            var left = _report.LeftMargin;

            var tableWidth = _report.PageMaxWidth;
            const float tableHeight = sectionTitleHeight + emptyRowHeight;

            var table = new Table(_report.LeftMargin, top, tableWidth, tableHeight);
            table.Border.Width = 0.0f;
            table.Border.Color = Grayscale.Black;
            table.Border.LineStyle = LineStyle.None;
            table.BackgroundColor = RgbColor.White;
            table.CellSpacing = 0.0f;
            table.CellDefault.Align = TextAlign.Left;
            table.CellDefault.VAlign = VAlign.Top;
            table.CellDefault.Padding.Value = 0.0f;
            table.CellDefault.Border.Width = 0.0f;
            table.CellDefault.Border.LineStyle = LineStyle.None;
            table.CellDefault.Border.Color = RgbColor.White;


            table.Columns.Add(tableWidth);

            var row = table.Rows.Add(sectionTitleHeight);

            var cell = row.Cells.Add(
                new Label(sectionTitle, 0.0f, 0.0f, tableWidth,
                    sectionFontSize + 2f, Fonts.CalibriBold, sectionFontSize));
            cell.Border.Bottom.LineStyle = LineStyle.Solid;
            cell.Border.Bottom.Width = 1.5f;
            cell.Border.Bottom.Color = RgbColor.Black;

            row = table.Rows.Add(emptyRowHeight);
            row.Cells.Add(string.Empty);

         
            var score = 0;
            var regionAssessment = string.Empty;

         
            if (_dataSource.OverallPerformance != null)
            {
                score = Convert.ToInt32(_dataSource.OverallPerformance.Score);
                regionAssessment = _dataSource.OverallPerformance.Assessment.GetDisplayName();
            }

            var assessmentTypes = Enum.GetValues(typeof(AssessmentType)).Cast<AssessmentType>().ToList();
            var assessments = assessmentTypes.OrderBy(a => (int)a).Select(a => a.GetDisplayName()).ToArray();

            top = top + 30;


            const float radius = 17.5f;
            const float valueFontSize = 24f;
            const float nameLeftOffset = 45f;

            var percentileBullet = new BulletScore
            {
                Top = top,
                Left = left,
                Radius = radius,
                Value = score.ToString(),
                ValueFont = Fonts.CalibriBold,
                ValueFontSize = valueFontSize
            };
            page.Elements.Add(percentileBullet);
            page.Elements.Add(new Label("Corporate Governance Score", left + nameLeftOffset, top + 3f, 250f, 12f, Fonts.CalibriBold, 10f, TextAlign.Left, RgbColor.Black));
            page.Elements.Add(new Line(left + nameLeftOffset, top + 15f, left + 165f, top + 15f, 0.5f, RgbColor.Black));

            if (assessments.Any())
            {
                const float assessmentsTableHeight = 55f;
                const float rowHeight = 8f;
                const float columnWidth = 100f;
                const float assessmentLeftOffset = 45f;
                const float assessmentTopOffset = 20f;
                const float assessmentFontSize = 7f;

                var assessmentsTable = new Table(left + assessmentLeftOffset, top + assessmentTopOffset, columnWidth, assessmentsTableHeight, Fonts.CalibriLight, assessmentFontSize);
                assessmentsTable.Border.Width = 0.0f;
                assessmentsTable.CellSpacing = 0.0f;
                assessmentsTable.CellDefault.Align = TextAlign.Left;
                assessmentsTable.CellDefault.VAlign = VAlign.Top;
                assessmentsTable.CellDefault.Padding.Value = 0.0f;
                assessmentsTable.CellDefault.Border.Color = RgbColor.Blue;
                assessmentsTable.CellDefault.Border.Width = 0.0f;
                assessmentsTable.CellDefault.Border.LineStyle = LineStyle.None;
                assessmentsTable.Border.Color = Grayscale.Black;
                assessmentsTable.RepeatColumnHeaderCount = 0;
                assessmentsTable.RepeatRowHeaderCount = 0;
                assessmentsTable.Columns.Add(columnWidth);

                foreach (var assessment in assessments)
                {
                    row = assessmentsTable.Rows.Add(rowHeight);
                    if (assessment == regionAssessment)
                        row.Cells.Add(assessment, Fonts.CalibriRegular, assessmentFontSize + 1f, RgbColor.Black, RgbColor.White, 1);
                    else
                        row.Cells.Add(assessment, Fonts.CalibriRegular, assessmentFontSize, RgbColor.DimGray, RgbColor.White, 1);
                }

                page.Elements.Add(assessmentsTable);
            }


            if (_dataSource.CompanyProfile.FullProfile && _dataSource.CompanyProfile.Outlook.HasValue)
                AddOutlookElement(page.Elements, _dataSource.CompanyProfile.Outlook.Value, left + 200, top - 1);

            return table;
        }

        private void AddOutlookElement(Group pageElements, OutlookType outlook, float x, float y)
        {
            if (outlook == OutlookType.Neutral)
                pageElements.Add(new Image(ImageData.GetImage(OutlookArrowRight), x - 15f, y, 0.07f) { Align = Align.Left, VAlign = VAlign.Top });

            if (outlook == OutlookType.Positive)
                pageElements.Add(new Image(ImageData.GetImage(OutlookArrowUp), x - 15f, y, 0.07f) { Align = Align.Left, VAlign = VAlign.Top });

            if (outlook == OutlookType.Negative)
                pageElements.Add(new Image(ImageData.GetImage(OutlookArrowDown), x - 15f, y, 0.07f) { Align = Align.Left, VAlign = VAlign.Top });


            pageElements.Add(new Label("Outlook", x + 35, y + 5, 50f, 10f, Fonts.CalibriBold, 9, TextAlign.Left, RgbColor.Black));
            pageElements.Add(new Line(x + 35f, y + 16, x + 135f, y +16, 0.5f, RgbColor.Black));
            pageElements.Add(new Label(outlook.ToString(), x + 35, y + 20, 50f, 10f, Fonts.CalibriRegular, 9, TextAlign.Left, RgbColor.Black));
        }


        private static bool CompanyHasNoPeersOrSingle(IList<GovernanceCompanyRating> industryPeers, Guid referenceCompany)
        {
            return industryPeers.Count == 0 || (industryPeers.Count == 1 && industryPeers[0].CompanyId == referenceCompany);
        }

        private void AddRelativePerformance(Page page, float left, float top)
        {
            const string messageWhenNoPeers = "There are no peers in the selected reference universe";


            page.Elements.Add(new Label("Relative Performance", left, top, 200, 15, Fonts.CalibriBold, 14));
            page.Elements.Add(new Line(left, top + 20, 550, top + 20, 1.5f, Colors.LineColor));

            float xTable = left + 185;
            top = top - 20;
            
         
            var percentile = 0;


            if (_dataSource.OverallPerformance != null)
            {
                var regionPerformance = _dataSource.OverallPerformance.Performances.Where(p => p.PerformanceType == PerformanceType.Region).ToList();

                if (regionPerformance.Count == 1)
                {
                    percentile = ScoreConversion.GetRoundedScore(regionPerformance[0].Percentile);
                }
            }

            const float radius = 17.5f;
            const float valueFontSize = 24f;
            const float nameLeftOffset = 45f;

            var percentileBullet = new PercentileBullet
            {
                Top = top + 50,
                Left = left,
                Radius = radius,
                Value = percentile,
                ValueFont = Fonts.CalibriBold,
                ValueFontSize = valueFontSize
            };
            page.Elements.Add(percentileBullet);
            page.Elements.Add(new Label("Regional Percentile", left + nameLeftOffset, top + 53f, 250f, 12f, Fonts.CalibriBold, 10f, TextAlign.Left, RgbColor.Black));
            page.Elements.Add(new Line(left + nameLeftOffset, top + 65f, left + 130f, top + 65f, 0.5f, RgbColor.Black));
            page.Elements.Add(new Label(_dataSource.CompanyProfile.RegionName, left + nameLeftOffset, top + 70f, 250f, 10f, Fonts.CalibriRegular, 8f, TextAlign.Left, RgbColor.Black));
         
            top = top + 15;

            var companyColor = new RgbColor(49, 163, 150);

            page.Elements.Add(new Label("Top 5 Companies", xTable + 10, top + 40f, 100f, 10f, Fonts.CalibriBold, 10, TextAlign.Left, RgbColor.Black));
            page.Elements.Add(new Label("Score", xTable + 142, top + 40f, 50f, 10f, Fonts.CalibriBold, 10, TextAlign.Left, RgbColor.Black));
            page.Elements.Add(new Line(xTable, top + 50f, xTable + 170f, top + 50f, 1f, RgbColor.Black));

            float yRow = top + 55f;

            if (_dataSource.RelativePerformance == null) return;

            if (CompanyHasNoPeersOrSingle(_dataSource.RelativePerformance.Top5List, _dataSource.CompanyId))
            {
                page.Elements.Add(new Label(string.Format("{0}.", messageWhenNoPeers), xTable, yRow, 340f, 15f,
                    Fonts.CalibriLight, 10f, TextAlign.Center, RgbColor.Black));
            }
            else
            {
                foreach (var topPerformer in _dataSource.RelativePerformance.Top5List)
                {
                    page.Elements.Add(new Label(string.Format("{0}.", topPerformer.Rank), xTable, yRow, 50f, 10f,
                        Fonts.CalibriLight, 8f, TextAlign.Left, RgbColor.Black));
                    var font = Fonts.CalibriLight;
                    var color = RgbColor.Black;

                    if (topPerformer.CompanyId == _dataSource.CompanyId)
                    {
                        color = companyColor;
                        font = Fonts.CalibriBold;
                    }

                    var companyName = topPerformer.CompanyName;

                    if (topPerformer.CompanyName.Length > 35)
                    {
                        companyName = topPerformer.CompanyName.Substring(0, 35) + " ...";
                    }

                    page.Elements.Add(new Label(companyName, xTable + 10f, yRow, 140f, 10f, font,
                        8f, TextAlign.Left, color));

                    page.Elements.Add(new Label(topPerformer.Score.ToString("#0"), xTable + 150f, yRow, 50f, 10f,
                        font, 8f, TextAlign.Left, color));

                    page.Elements.Add(new Line(xTable, yRow + 9, xTable + 170f, yRow + 9, 0.5f, RgbColor.Black));
                    yRow = yRow + 15;
                }
            }

            xTable = left + 370;

            var marketCapitalization = string.Format("(Market cap ${0}-${1}bn)",
                Convert.ToInt32(_dataSource.RelativePerformance.MarketCapRangeFrom/1000),
                Convert.ToInt32(_dataSource.RelativePerformance.MarketCapRangeTo/1000));

            page.Elements.Add(new Label("Peers", xTable + 5, top + 40f, 100f, 10f, Fonts.CalibriBold, 10, TextAlign.Left, RgbColor.Black));
            page.Elements.Add(new Label(marketCapitalization, xTable + 30, top + 41f, 120f, 8f, Fonts.CalibriLight, 8, TextAlign.Left, RgbColor.Black));
            page.Elements.Add(new Label("Score", xTable + 142, top + 40f, 50f, 10f, Fonts.CalibriBold, 10, TextAlign.Left, RgbColor.Black));
            page.Elements.Add(new Line(xTable, top + 50f, xTable + 170f, top + 50f, 1f, RgbColor.Black));

            yRow = top + 55f;


            if (!CompanyHasNoPeersOrSingle(_dataSource.RelativePerformance.Top5List, _dataSource.CompanyId))
            {
                foreach (var topPerformer in _dataSource.RelativePerformance.PeersList)
                {
                    var font = Fonts.CalibriLight;
                    var color = RgbColor.Black;
                    if (topPerformer.CompanyId == _dataSource.CompanyId)
                    {
                        color = companyColor;
                        font = Fonts.CalibriBold;
                    }

                    var companyName = topPerformer.CompanyName;

                    if (topPerformer.CompanyName.Length > 35)
                    {
                        companyName = topPerformer.CompanyName.Substring(0, 35) + " ...";
                    }
 
                    page.Elements.Add(new Label(companyName, xTable + 5, yRow, 140f, 10f, font, 8f,
                        TextAlign.Left, color));

                    page.Elements.Add(new Label(topPerformer.Score.ToString("#0"), xTable + 150f, yRow, 50f, 10f,
                        font, 8f, TextAlign.Left, color));

                    page.Elements.Add(new Line(xTable, yRow + 9, xTable + 170f, yRow + 9, 0.5f, RgbColor.Black));
                    yRow = yRow + 15;
                }
            }

        }

        private Table AddRelativePerformanceDetails(float top)
        {
            const string sectionTitle = "Relative Performance Details";
            const string sectionSubtitle1 = "Percentile Comparisons";
            const string sectionSubtitle2 = "Key Corporate Governance Issues";
            
            const float emptyRowHeight = 10f;
            const float sectionTitleHeight = 20f;
            const float sectionSubtitleHeight = 20f;

            const float sectionFontSize = 14f;

            var isFullVersion = _dataSource.CompanyProfile.FullProfile;

            var tableWidth = _report.PageMaxWidth;

            var subTable1 = PercentileComparisons();
            var subTable1Height = subTable1.GetRequiredHeight() + 5;

            var subTable2 = KeyCorporateGovernanceIssues();
            var subTable2Height = subTable2.GetRequiredHeight() + 5;

            var tableHeight = subTable1Height + subTable2Height + sectionTitleHeight + sectionSubtitleHeight * 2 + emptyRowHeight * 4;

            var table = new Table(_report.LeftMargin, top, tableWidth, tableHeight);
            table.Border.Width = 0.0f;
            table.Border.Color = Grayscale.Black;
            table.Border.LineStyle = LineStyle.None;
            table.BackgroundColor = RgbColor.White;
            table.CellSpacing = 0.0f;
            table.CellDefault.Align = TextAlign.Left;
            table.CellDefault.VAlign = VAlign.Top;
            table.CellDefault.Padding.Value = 0.0f;
            table.CellDefault.Border.Width = 0.0f;
            table.CellDefault.Border.LineStyle = LineStyle.None;
            table.CellDefault.Border.Color = RgbColor.White;


            table.Columns.Add(tableWidth);

            var row = table.Rows.Add(sectionTitleHeight);

            Cell cell;

            cell = row.Cells.Add(
                new Label(sectionTitle, 0.0f, 0.0f, tableWidth,
                    sectionFontSize + 2f, Fonts.CalibriBold, sectionFontSize));
            cell.Border.Bottom.LineStyle = LineStyle.Solid;
            cell.Border.Bottom.Width = 1.5f;
            cell.Border.Bottom.Color = RgbColor.Black;

            row = table.Rows.Add(sectionSubtitleHeight);
            cell = row.Cells.Add(
                new Label(sectionSubtitle1, 0.0f, 0.0f, tableWidth - 80f,
                    sectionFontSize + 2f, Fonts.CalibriBold, sectionFontSize, TextAlign.Right));
            cell.Padding.Top = isFullVersion ? 10f : 5f;
            cell.Padding.Right = 80f;

            row = table.Rows.Add(subTable1Height);
            row.Cells.Add(subTable1);

            row = table.Rows.Add(sectionSubtitleHeight);
            cell = row.Cells.Add(
                new Label(sectionSubtitle2, 0.0f, 0.0f, tableWidth,
                    sectionFontSize + 2f, Fonts.CalibriBold, sectionFontSize));
            cell.Padding.Top = isFullVersion ? 10f : 5f;

            row = table.Rows.Add(subTable2Height);
            row.Cells.Add(subTable2);

            return table;
        }

        private Table PercentileComparisons()
        {
            const float headerHeight = 35f;
            const float rowHeight = 26f;

            const float sectionFontSize = 8f;
            var columns = new[] {0.0f, 100f, 60f, 95f, 140f, 140f};

            var tableWidth = _report.PageMaxWidth - 5;
            var tableHeight = headerHeight + rowHeight + 5;

           

            var regionPercentile = 0;
            var regionCount = 0;
            var peergroupPercentile = 0;
            var peergroupCount = 0;

            if (_dataSource.OverallPerformance != null)
            {
                var regionPerformance = _dataSource.OverallPerformance.Performances.Where(p => p.PerformanceType == PerformanceType.Region).ToList();

                if (regionPerformance.Count == 1)
                {
                    regionPercentile = ScoreConversion.GetRoundedScore(regionPerformance[0].Percentile);
                    regionCount = regionPerformance[0].GroupCount;
                }

                var peergroupPerformance = _dataSource.OverallPerformance.Performances.Where(p => p.PerformanceType == PerformanceType.PeerGroup).ToList();

                if (peergroupPerformance.Count == 1)
                {
                    peergroupPercentile = ScoreConversion.GetRoundedScore(peergroupPerformance[0].Percentile);
                    peergroupCount = peergroupPerformance[0].GroupCount;
                }
            }


            var style = new FormattedTextAreaStyle(Fonts.CalibriFontFamily, 8f, false)
            {
                Paragraph = { Align = TextAlign.Center, Indent = 0, SpacingAfter = 0, AllowOrphanLines = false }
            };


            var table = new Table(0.0f, 0.0f, tableWidth, tableHeight);
            table.Border.Width = 0.0f;
            table.Border.Color = Grayscale.Black;
            table.Border.LineStyle = LineStyle.None;
            table.BackgroundColor = RgbColor.White;
            table.CellSpacing = 0.0f;
            table.CellDefault.Align = TextAlign.Center;
            table.CellDefault.VAlign = VAlign.Center;
            table.CellDefault.Padding.Value = 0.0f;
            table.CellDefault.Border.Width = 0.2f;
            table.CellDefault.Border.LineStyle = LineStyle.Solid;
            table.CellDefault.Border.Color = RgbColor.Black;


            table.Columns.Add(columns[1]);
            table.Columns.Add(columns[2]);
            table.Columns.Add(columns[3]);
            table.Columns.Add(columns[4]);
            table.Columns.Add(columns[4]);

            var row = table.Rows.Add(headerHeight);

            Cell cell;

            cell = row.Cells.Add(string.Empty);
            cell.Border.Left.LineStyle = LineStyle.None;
            cell.Border.Top.LineStyle = LineStyle.None;
            row.Cells.Add(
                new Label("Score", 0.0f, 0.0f, columns[2],
                    sectionFontSize + 2f, Fonts.CalibriBold, sectionFontSize, TextAlign.Center));
            row.Cells.Add(
                new Label("Assessment", 0.0f, 0.0f, columns[3],
                    sectionFontSize + 2f, Fonts.CalibriBold, sectionFontSize, TextAlign.Center));

            var region = string.Format("<p><b>Region ({0} companies)</b></p><p><b>{1}</b></p>", regionCount, _dataSource.CompanyProfile.RegionName);
            var regionTextArea = new FormattedTextArea(region, 0.0f, 0.0f, columns[3], headerHeight - 3f, style);
            var topTextArea = (headerHeight - regionTextArea.GetRequiredHeight())/2;
            topTextArea = topTextArea < 0 ? 0 : topTextArea;
            regionTextArea = new FormattedTextArea(region, 0.0f, topTextArea, columns[3], headerHeight - 3f, style);

            row.Cells.Add(regionTextArea);

            var industry = string.Format("<p><b>Industry ({0} companies)</b></p><p><b>{1}</b></p>", peergroupCount, _dataSource.CompanyProfile.Industry);
            var industryTextArea = new FormattedTextArea(industry, 0.0f, 0.0f, columns[3], headerHeight - 3f, style);
            topTextArea = (headerHeight - industryTextArea.GetRequiredHeight()) / 2;
            topTextArea = topTextArea < 0 ? 0 : topTextArea;
            industryTextArea = new FormattedTextArea(industry, 0.0f, topTextArea, columns[3], headerHeight - 3f, style);

            row.Cells.Add(industryTextArea);


            if (_dataSource.OverallPerformance == null) return table;

            row = table.Rows.Add(rowHeight);
            row.Cells.Add(
                new Label("Overall Score", 0.0f, 0.0f, columns[1],
                    sectionFontSize + 2f, Fonts.CalibriBold, sectionFontSize, TextAlign.Center));
            const float radius = 10f;
            var left = columns[2]/2 - radius;

            var score = Convert.ToInt32(_dataSource.OverallPerformance.Score).ToString(CultureInfo.InvariantCulture);
            row.Cells.Add(new BulletScore
            {
                Top = 3,
                Left = left,
                Radius = radius,
                Value = score,
                ValueFont = Fonts.CalibriBold,
                ValueFontSize = 10f
            });
            
            row.Cells.Add(
                new Label(_dataSource.OverallPerformance.Assessment.GetDisplayName(), 0.0f, 0.0f, columns[3],
                    sectionFontSize + 2f, Fonts.CalibriRegular, sectionFontSize, TextAlign.Center));

            row.Cells.Add(new PercentileSlider
            {
                Top = 0.0f,
                Left = 0.0f,
                Width = columns[4],
                Heigth = rowHeight,
                Radius = 8,
                Value = regionPercentile,
                ValueFont = Fonts.CalibriBold,
                ValueFontSize = 8f
            });

            row.Cells.Add(new PercentileSlider
            {
                Top = 0.0f,
                Left = 0.0f,
                Width = columns[5],
                Heigth = rowHeight,
                Radius = 8,
                Value = peergroupPercentile,
                ValueFont = Fonts.CalibriBold,
                ValueFontSize = 8f
            });

            return table;
        }

        private Table KeyCorporateGovernanceIssues()
        {
            const float rowHeight = 26f;

            const float sectionFontSize = 8f;
            
            var style = new FormattedTextAreaStyle(Fonts.CalibriFontFamily, 8f, false)
            {
                Paragraph = { Align = TextAlign.Left, Indent = 0, SpacingAfter = 0, AllowOrphanLines = false }
            };
            
            var issues = _dataSource.IssuesPerformance
                .Where(i => i.Number != "CG.0")
                .OrderBy(i => i.Number)
                .ToList();
           
            var columns = new[] { 0.0f, 100f, 60f, 95f, 140f, 140f };

            var tableWidth = _report.PageMaxWidth - 5;
            var tableHeight = (rowHeight * issues.Count) + 5;

            var table = new Table(0.0f, 0.0f, tableWidth, tableHeight);
            table.Border.Width = 0.0f;
            table.Border.Color = Grayscale.Black;
            table.Border.LineStyle = LineStyle.None;
            table.BackgroundColor = RgbColor.White;
            table.CellSpacing = 0.0f;
            table.CellDefault.Align = TextAlign.Center;
            table.CellDefault.VAlign = VAlign.Center;
            table.CellDefault.Padding.Value = 0.0f;
            table.CellDefault.Border.Width = 0.2f;
            table.CellDefault.Border.LineStyle = LineStyle.Solid;
            table.CellDefault.Border.Color = RgbColor.Black;

            table.Columns.Add(columns[1]);
            table.Columns.Add(columns[2]);
            table.Columns.Add(columns[3]);
            table.Columns.Add(columns[4]);
            table.Columns.Add(columns[4]);


            Cell cell;

            foreach (var issue in issues)
            {
                var issueName = string.Format("<p><b>{0}</b></p>", issue.Name);


                var score = ScoreConversion.GetRoundedScore(issue.Score)
                    .ToString(CultureInfo.InvariantCulture);

                var formattedTextArea = new FormattedTextArea(issueName, 5.0f, 3.0f, columns[1] - 10f, rowHeight - 3f, style);
                
                var row = table.Rows.Add(rowHeight);
                cell = row.Cells.Add(formattedTextArea);
                cell.Align = TextAlign.Left;

                const float radius = 10f;
                var left = columns[2]/2 - radius;
                row.Cells.Add(new BulletScore
                {
                    Top = 3,
                    Left = left,
                    Radius = radius,
                    Value = score,
                    ValueFont = Fonts.CalibriBold,
                    ValueFontSize = 10f
                });

                row.Cells.Add(
                    new Label(issue.Assessment.GetDisplayName(), 0.0f, 0.0f, columns[3],
                        sectionFontSize + 2f, Fonts.CalibriRegular, sectionFontSize, TextAlign.Center));
                
                var regionPerformance = issue.Performances.Where(p => p.PerformanceType == PerformanceType.Region).ToList();
                if (regionPerformance.Count == 1)
                {
                    row.Cells.Add(new PercentileSlider
                    {
                        Top = 0.0f,
                        Left = 0.0f,
                        Width = columns[4],
                        Heigth = rowHeight,
                        Radius = 8,
                        Value = ScoreConversion.GetRoundedScore(regionPerformance[0].Percentile),
                        ValueFont = Fonts.CalibriBold,
                        ValueFontSize = 8f
                    });
                }
                else
                {
                    row.Cells.Add(string.Empty);
                }

                var peergroupPerformance = issue.Performances.FirstOrDefault(p => p.PerformanceType == PerformanceType.PeerGroup);
                if (peergroupPerformance != null)
                {
                    row.Cells.Add(new PercentileSlider
                    {
                        Top = 0.0f,
                        Left = 0.0f,
                        Width = columns[5],
                        Heigth = rowHeight,
                        Radius = 8,
                        Value = ScoreConversion.GetRoundedScore(peergroupPerformance.Percentile),
                        ValueFont = Fonts.CalibriBold,
                        ValueFontSize = 8f
                    });
                }
                else
                {
                    row.Cells.Add(string.Empty);
                }
            }

            return table;
        }

        private Table AddOverview(float top)
        {
            const string sectionTitle = "Overview";

            const float sectionTitleHeight = 20f;

            const float sectionFontSize = 14f;

            var tableWidth = _report.PageMaxWidth;


            var style = new FormattedTextAreaStyle(Fonts.CalibriFontFamily, 9f, false)
            {
                Paragraph = { Align = TextAlign.Justify, Indent = 0, SpacingAfter = 0, AllowOrphanLines = false }
            };

            var text = string.IsNullOrEmpty(_dataSource.CompanyProfile.AnalystView)
                ? string.Empty
                : _dataSource.CompanyProfile.AnalystView;

            var overview = string.Format("<p>{0}</p>", text);

            const float rowHeight = 40f;

            var length = overview.Length;

            if (overview.Length > 600)
            {
                overview = overview.Substring(0, 600) + " ...</p>";
                length = 600;
            }

            var formattedTextArea = new FormattedTextArea(overview, 0.0f, 0.0f, tableWidth - 5f, rowHeight, style);

            while (formattedTextArea.HasOverflowText())
            {
                length -= 18;

                overview = overview.Substring(0, length) + " ...</p>";

                formattedTextArea = new FormattedTextArea(overview, 0.0f, 0.0f, tableWidth - 5f, rowHeight, style);
            }



            var tableHeight = sectionTitleHeight + rowHeight + 10f;

            var table = new Table(_report.LeftMargin, top, tableWidth, tableHeight);
            table.Border.Width = 0.0f;
            table.Border.Color = Grayscale.Black;
            table.Border.LineStyle = LineStyle.None;
            table.BackgroundColor = RgbColor.White;
            table.CellSpacing = 0.0f;
            table.CellDefault.Align = TextAlign.Left;
            table.CellDefault.VAlign = VAlign.Top;
            table.CellDefault.Padding.Value = 0.0f;
            table.CellDefault.Border.Width = 0.0f;
            table.CellDefault.Border.LineStyle = LineStyle.None;
            table.CellDefault.Border.Color = RgbColor.White;


            table.Columns.Add(tableWidth);

            var row = table.Rows.Add(sectionTitleHeight);

            var cell = row.Cells.Add(
                new Label(sectionTitle, 0.0f, 0.0f, tableWidth,
                    sectionFontSize + 2f, Fonts.CalibriBold, sectionFontSize));
            cell.Border.Bottom.LineStyle = LineStyle.Solid;
            cell.Border.Bottom.Width = 1.5f;
            cell.Border.Bottom.Color = RgbColor.Black;

            row = table.Rows.Add(rowHeight);
            row.Cells.Add(
                new FormattedTextArea(overview, 0.0f, 5.0f, tableWidth - 5f, rowHeight, style));

            return table;
        }

        private void AddAnalystViwSecondPage(String remainingAnalystView)
        {
            var style = new FormattedTextAreaStyle(Fonts.CalibriFontFamily, 10f, false)
            {
                Paragraph = { Align = TextAlign.Justify, Indent = 0, SpacingAfter = 5, AllowOrphanLines = false }
            };
            var currentYOffset = 15f;
            var new_page = _report.NewPage();
            _report.Pages.Add(new_page);
            var formattedTextArea = new FormattedTextArea(remainingAnalystView, 0, currentYOffset, 500, 500, style);
            new_page.AddElement(formattedTextArea);
        }

        private Table AddAnalystView()
        {
            var tableWidth = _report.PageMaxWidth;
            const float tableTop = 25f;
            const float emptyRowHeight = 10f;

            const float sectionTitleHeight = 22f;


            var style = new FormattedTextAreaStyle(Fonts.CalibriFontFamily, 10f, false)
            {
                Paragraph = { Align = TextAlign.Justify, Indent = 0, SpacingAfter = 5, AllowOrphanLines = false }
            };

            var analystView = string.IsNullOrEmpty(_dataSource.CompanyProfile.AnalystView)
                ? string.Empty
                : _dataSource.CompanyProfile.AnalystView;

            var formattedTextArea = new FormattedTextArea(analystView, 0.0f, 0.0f, tableWidth, 500f, style);
            var rowHeight = formattedTextArea.GetRequiredHeight() + 5f;



            var tableHeight = sectionTitleHeight + emptyRowHeight + rowHeight + 10f;
            
            
            var table = new Table(_report.LeftMargin, tableTop, tableWidth, tableHeight);
            table.Border.LineStyle = LineStyle.None;
            table.CellDefault.Border.LineStyle = LineStyle.None;
            table.Border.Width = 0.0f;
            table.Border.Color = Grayscale.Black;
            table.Border.LineStyle = LineStyle.None;
            table.BackgroundColor = RgbColor.White;
            table.CellSpacing = 0.0f;
            table.CellDefault.Align = TextAlign.Left;
            table.CellDefault.VAlign = VAlign.Top;
            table.CellDefault.Padding.Value = 0.0f;
            table.CellDefault.Border.Width = 0.0f;
            table.CellDefault.Border.LineStyle = LineStyle.None;
            table.CellDefault.Border.Color = RgbColor.White;

            table.Columns.Add(tableWidth);

            var row = table.Rows.Add(sectionTitleHeight);

            const string sectionName = "<p><font color='FFFFFF'><b>Analyst View</b></font></p>";

            var cell = row.Cells.Add(new FormattedTextArea(sectionName, 13f, 1f, 120f, 16f, Fonts.CalibriFontFamily, 16, false));
            cell.BackgroundColor = Colors.SectionColor;
            cell.VAlign = VAlign.Center;
            cell.Align = TextAlign.Left;

            row = table.Rows.Add(emptyRowHeight);
            row.Cells.Add(string.Empty);

            var remainingAnalystViewText = string.Empty;
            if (analystView.Length > 4900)
            {
                var valueToSplit = analystView.Substring(0,4850).LastIndexOf(".") + 1;
                var splitedComment = analystView.Substring(0, valueToSplit);
                remainingAnalystViewText = analystView.Substring(valueToSplit);
                analystView = splitedComment;
            }
            if (!String.IsNullOrEmpty(remainingAnalystViewText))
            {
                AddAnalystViwSecondPage(remainingAnalystViewText);
            }
            formattedTextArea = new FormattedTextArea(analystView, 0.0f, 0.0f, tableWidth, rowHeight, style);

            row = table.Rows.Add(rowHeight);
            row.Cells.Add(formattedTextArea);
            return table;
        }
    }
}
